package com.zhijian.warehouse.manage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.zhijian.util.BeanUtil;
import com.zhijian.util.page.Page;
import com.zhijian.warehouse.manage.dao.StoreMapper;
import com.zhijian.warehouse.manage.entity.dto.stock.StockActionDto;
import com.zhijian.warehouse.manage.entity.dto.stock.StockStorageDto;
import com.zhijian.warehouse.manage.entity.export.StoreExport;
import com.zhijian.warehouse.manage.entity.po.Store;
import com.zhijian.warehouse.manage.entity.vo.request.StoreSaveOrUpdateVo;
import com.zhijian.warehouse.manage.entity.vo.request.StoreSearchVo;
import com.zhijian.warehouse.manage.entity.vo.request.StoreWarehouseLocationSearchVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreWarehouseLocationProjectVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreWarehouseLocationVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreWarehouseVo;
import com.zhijian.warehouse.manage.service.StoreOptRecordService;
import com.zhijian.warehouse.manage.service.StoreService;
import com.zhijian.warehouse.manage.service.WarehouseService;
import com.zhijian.warehouse.manage.util.AssertCommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 库存管理业务处理层
 *
 * @author auto
 * @version: 1.0
 * @date 2024-10-27 13:42:54
 */
@Slf4j
@Service
public class StoreServiceImpl implements StoreService {

    @Autowired
    private StoreMapper mapper;

    @Autowired
    private StoreOptRecordService storeOptRecordService;

    @Autowired
    private WarehouseService warehouseService;

    @Override
    public Store selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public StoreVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public void deleteByIdList(List<Long> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return;
        }
        mapper.deleteByIdList(idList);
    }

    @Override
    public Long insert(Store store) {
        Date now = new Date();
        store.setCreateTime(now);
        store.setUpdateTime(now);
        return mapper.insert(store) > 0 ? store.getId() : 0L;
    }

    @Override
    public Long insertSelective(Store store) {
        Date now = new Date();
        store.setCreateTime(now);
        store.setUpdateTime(now);
        return mapper.insertSelective(store) > 0 ? store.getId() : 0L;
    }

    @Override
    public boolean update(Store store) {
        Date now = new Date();
        store.setUpdateTime(now);
        return mapper.updateByPrimaryKey(store) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(Store record) {
        Date now = new Date();
        record.setUpdateTime(now);
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public boolean save(StoreSaveOrUpdateVo saveOrUpdateVo) {
        Store store = new Store();
        BeanUtils.copyProperties(saveOrUpdateVo, store);
        return this.insert(store) != 0;
    }

    @Override
    public boolean modify(StoreSaveOrUpdateVo saveOrUpdateVo) {
        Store old = this.selectById(saveOrUpdateVo.getId());
        AssertCommonUtil.notNull(old, "此数据不存在或者已被删除");
        Store store = new Store();
        BeanUtils.copyProperties(saveOrUpdateVo, store);
        return this.update(store);
    }

    @Override
    public StoreVo selectOne(StoreSearchVo storeSearchVo) {
        return mapper.selectOne(storeSearchVo);
    }

    @Override
    public Integer count(StoreSearchVo storeSearchVo) {
        return mapper.count(storeSearchVo);
    }

    @Override
    public List<StoreVo> selectList(StoreSearchVo storeSearchVo) {
        return mapper.selectList(storeSearchVo);
    }

    @Override
    public List<StoreExport> selectStoreExportList(StoreSearchVo param) {
        return mapper.selectStoreExportList(param);
    }

    @Override
    public void flushStore() {
        Integer count = this.count(StoreSearchVo.builder().build());
        if (count > 0) {
            //刷新月初库存
            mapper.flushStartDay();
        }
    }

    @Override
    public void flushStoreEnd() {
        Integer count = this.count(StoreSearchVo.builder().build());
        if (count > 0) {
            //刷新月末库存
            mapper.flushStoreEnd();
        }
    }

    @Override
    public Page<StoreVo> selectPage(StoreSearchVo storeSearchVo) {
        AssertCommonUtil.check(Objects.isNull(storeSearchVo.getPageNum()) || Objects.isNull(storeSearchVo.getPageSize()), "分页参数不能为空");
        //先直接查总数
        if (BeanUtil.isNotEmpty(storeSearchVo.getProductStatusType())) {
            if (storeSearchVo.getProductStatusType() == 2) {
                storeSearchVo.setProductStatusList(Arrays.asList(1, 2));
            }
        }
        int count = count(storeSearchVo);
        //分页
        Page<StoreVo> page = new Page<>(true, count, storeSearchVo.getPageNum(), storeSearchVo.getPageSize());
        storeSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<StoreVo> responseVos = this.selectList(storeSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public Page<StoreWarehouseLocationProjectVo> selectStoreWarehouseLocationProject(StoreWarehouseLocationSearchVo storeSearchVo) {
        AssertCommonUtil.check(Objects.isNull(storeSearchVo.getPageNum()) || Objects.isNull(storeSearchVo.getPageSize()), "分页参数不能为空");
        //分组查询查询产品id
        int count = mapper.selectWarehouseLocationProjectCount(storeSearchVo);
        //分页
        Page<StoreWarehouseLocationProjectVo> page = new Page<>(true, count, storeSearchVo.getPageNum(), storeSearchVo.getPageSize());
        storeSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<StoreWarehouseLocationProjectVo> responseVos = mapper.selectWarehouseLocationProjectList(storeSearchVo);
        if (BeanUtil.isEmpty(responseVos))
            return page;
        responseVos.parallelStream().forEach(vo -> {
            String warehouseIds = vo.getWarehouseIds();
            //根据仓库ids 查询仓库列表
            List<Long> warehouseIdsList = Arrays.stream(warehouseIds.split(","))
                    .map(Long::valueOf) // 将每个 String 转换为 Long
                    .collect(Collectors.toList());
            vo.setStoreWarehouseVos(getWarehouseWithLocations(warehouseIdsList, vo.getProductId()));
        });
        page.setData(responseVos);
        return page;
    }

    @Override
    public List<StoreWarehouseVo> getWarehouseWithLocations(List<Long> warehouseIdsList, Long productId) {
        if (BeanUtil.isNotEmpty(warehouseIdsList)) {
            //去重
            warehouseIdsList = warehouseIdsList.stream().distinct().collect(Collectors.toList());
        } else if (BeanUtil.isEmpty(productId) || BeanUtil.isEmpty(warehouseIdsList)) {
            return Collections.emptyList();
        }
        List<StoreWarehouseVo> warehouseVosList = warehouseService.selectByIds(warehouseIdsList);
      /*  // 根据仓库名称和产品 id 查询库存和库位信息
        warehouseVosList.forEach(warehouseVo -> {
            warehouseVo.setStoreWarehouseLocationVos(getStoreWarehouseLocations(warehouseVo.getId(), productId));
        });*/

        return warehouseVosList;
    }

    @Override
    public List<StoreWarehouseLocationVo> getStoreWarehouseLocations(Long warehouseVoId, Long productId) {
        AssertCommonUtil.check(BeanUtil.isEmpty(warehouseVoId) || BeanUtil.isEmpty(productId), "仓库或产品不能为空");
        List<StoreVo> storeVos = selectList(StoreSearchVo.builder()
                .warehouseId(warehouseVoId)
                .productId(productId)
                .build());
        List<StoreWarehouseLocationVo> storeWarehouseLocationVos = Collections.synchronizedList(new ArrayList<>());
        storeVos.parallelStream().forEach(storeVo -> {
            // 组装库位和库存
            storeWarehouseLocationVos.add(StoreWarehouseLocationVo.builder()
                    .id(storeVo.getWarehouseLocationId())
                    .name(storeVo.getWarehouseLocationName())
                    .productCount(storeVo.getProductCount())
                    .build());
        });

        return storeWarehouseLocationVos;
    }


    @Override
    public boolean insertBatch(List<Store> entities) {
        return CollectionUtil.isNotEmpty(entities) && mapper.insertBatch(entities) > 0;
    }

    @Transactional
    @Override
    public boolean stockAction(StockActionDto stockActionDto) {
        //保存库存操作记录
        storeOptRecordService.insertByStockActionDto(stockActionDto);
        //入库或出库
        stockInOrOut(stockActionDto);
        return true;
    }

    @Transactional
    @Override
    public boolean stockInOrOut(StockActionDto stockActionDto) {
        AssertCommonUtil.notNull(stockActionDto, "库存变更参数不能为空");
        List<StockStorageDto> stockStorageList = stockActionDto.getStockStorages();
        AssertCommonUtil.check(CollectionUtil.isEmpty(stockStorageList), "库存变更列表不能为空");

        //先根据仓库id分组
        Map<Long, List<StockStorageDto>> stockStorage = stockStorageList.stream().collect(Collectors.groupingBy(StockStorageDto::getWarehouseId));
        stockStorage.forEach((warehouseId, value) -> {
            List<StockStorageDto> stockStorages = new ArrayList<>();
            //同时根据商品id和库位id分组
            // 根据 productId 和 warehouseLocationId 分组
            Map<String, List<StockStorageDto>> groupedByProductAndLocation = value.stream()
                    .collect(Collectors.groupingBy(StockStorageDto::getProductIdLocationId));
            groupedByProductAndLocation.forEach((ProductIdWarehouseLocationId, stockStorageDtos) -> {
                AtomicReference<BigDecimal> totalNum = new AtomicReference<>(BigDecimal.ZERO);

                //总数量
                stockStorageDtos.forEach(p -> {
                    totalNum.set(totalNum.get().add(p.getCount()));
                });
                String warehouseLocationIdStr = ProductIdWarehouseLocationId.split("_")[0];
                String productIdStr = ProductIdWarehouseLocationId.split("_")[1];
                stockStorages.add(StockStorageDto.builder()
                        .productId(Long.valueOf(productIdStr))
                        .warehouseLocationId(Long.valueOf(warehouseLocationIdStr))
                        .warehouseId(warehouseId)
                        .count(totalNum.get())
                        .build());
            });
            //商品id
            List<Long> warehouseLocationIds = stockStorages.stream().map(StockStorageDto::getWarehouseLocationId).collect(Collectors.toList());
            List<Long> productIds = stockStorages.stream().map(StockStorageDto::getProductId).collect(Collectors.toList());
            //查询仓库现库存
            Map<Long, List<Store>> stockGroupLocationIdCollect = new HashMap<>();
            List<Store> stocks = mapper.selectByCommodityIds(warehouseLocationIds, productIds, warehouseId);
            //修改
            List<Store> stockUpdates = Collections.synchronizedList(new ArrayList<>());
            //新增
            List<Store> stockNews = Collections.synchronizedList(new ArrayList<>());
            //区分库位
            if (BeanUtil.isNotEmpty(stocks))
                stockGroupLocationIdCollect = stocks.stream().collect(Collectors.groupingBy(Store::getWarehouseLocationId));
            Map<Long, List<Store>> finalStockGroupLocationIdCollect = stockGroupLocationIdCollect;
            Map<Long, List<StockStorageDto>> stockStoreCollectors = stockStorages.stream().collect(Collectors.groupingBy(StockStorageDto::getWarehouseLocationId));
            stockStoreCollectors.forEach((warehouseLocationId, stockStorageDtos) -> {
                stockStorageDtos.parallelStream().forEach(p -> {
                    BigDecimal num = p.getCount().multiply(new BigDecimal(stockActionDto.getActionType().genre));
                    if (BeanUtil.isNotEmpty(finalStockGroupLocationIdCollect.get(warehouseLocationId))) {
                        Map<Long, List<Store>> collect = finalStockGroupLocationIdCollect.get(warehouseLocationId).stream().collect(Collectors.groupingBy(Store::getProductId));
                        //修改
                        if (BeanUtil.isNotEmpty(collect.get(p.getProductId()))) {
                            Store store = collect.get(p.getProductId()).get(0);
                            stockUpdates.add(Store.builder()
                                    .id(store.getId())
                                    .productCount(num.add(store.getProductCount()))
                                    .updateUserId(stockActionDto.getOptUserId())
                                    .build());
                        } else {
                            //新增
                            stockNews.add(buildStore(p, stockActionDto, num));
                        }
                    } else {
                        //新增
                        stockNews.add(buildStore(p, stockActionDto, num));
                    }
                });
            });

            if (BeanUtil.isNotEmpty(stockUpdates))
                mapper.batchUpdate(stockUpdates);
            if (BeanUtil.isNotEmpty(stockNews))
                this.insertBatch(stockNews);

        });
        return true;
    }

    public Store buildStore(StockStorageDto p, StockActionDto stockActionDto, BigDecimal num) {
        return Store.builder()
                .productCount(num)
                .productId(p.getProductId())
                .warehouseLocationId(p.getWarehouseLocationId())
                .warehouseId(p.getWarehouseId())
                .createUserId(stockActionDto.getOptUserId())
                .updateUserId(stockActionDto.getOptUserId())
                .createTime(new Date())
                .updateTime(new Date()).build();
    }

    @Override
    public List<Store> selectByCommodityIds(Long warehouseId, List<Long> warehouseLocationIds, List<Long> productIds) {
        return mapper.selectByCommodityIds(warehouseLocationIds, productIds, warehouseId);
    }

    @Override
    public String selectProduct(StoreSearchVo param) {
        if (BeanUtil.isEmpty(param.getWarehouseId()) || BeanUtil.isEmpty(param.getWarehouseLocationId()) || BeanUtil.isEmpty(param.getProductId()))
            return "0";
        StoreVo storeVo = this.selectOne(StoreSearchVo.builder()
                .warehouseId(param.getWarehouseId())
                .warehouseLocationId(param.getWarehouseLocationId())
                .productId(param.getProductId()).build());

        return storeVo.getProductCountInit();
    }

    @Override
    public List<Long> selectWarehouseId(Long productId) {
        return mapper.selectWarehouseId(productId);
    }
}
